package com.seadragon.app.ksr.parser;

import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.seadragon.app.ksr.model.Address;

@Service("addressParser")
public class AddressParserUSImpl implements AddressParser {
	private Logger logger = LoggerFactory.getLogger(AddressParserUSImpl.class);

	private static final Map<String, String> secondaryUnitMap = new HashMap<String, String>();
	private static final Map<String, String> streetDirectionMap = new HashMap<String, String>();
	private static final Map<String, String> streetTypeMap = new HashMap<String, String>();
	private static final Map<String, String> beforeStreetTypeMap = new HashMap<String, String>();
	
	static {
		secondaryUnitMap.put("APARTMENT","APT");
		secondaryUnitMap.put("APT", "APT");
		secondaryUnitMap.put("BASEMENT", "BSMT");
		secondaryUnitMap.put("BLDG", "BLDG");
		secondaryUnitMap.put("BSMT", "BSMT");
		secondaryUnitMap.put("BUILDING", "BLDG");
		secondaryUnitMap.put("DEPARTMENT", "DEPT");
		secondaryUnitMap.put("DEPT", "DEPT");
		secondaryUnitMap.put("FL", "FL");
		secondaryUnitMap.put("FLOOR", "FL");
		secondaryUnitMap.put("FRNT", "FRNT");
		secondaryUnitMap.put("FRONT", "FRNT");
		secondaryUnitMap.put("HANGAR", "HNGR");
		secondaryUnitMap.put("HNGR", "HNGR");
		secondaryUnitMap.put("LBBY", "LBBY");
		secondaryUnitMap.put("LOBBY", "LBBY");
		secondaryUnitMap.put("LOT", "LOT");
		secondaryUnitMap.put("LOWER", "LOWR");
		secondaryUnitMap.put("LOWR", "LOWR");
		secondaryUnitMap.put("OFC", "OFC");
		secondaryUnitMap.put("OFFICE", "OFC");
		secondaryUnitMap.put("PENTHOUSE", "PH");
		secondaryUnitMap.put("PH", "PH");
		secondaryUnitMap.put("PIER", "PIER");
		secondaryUnitMap.put("REAR", "REAR");
		secondaryUnitMap.put("RM", "RM");
		secondaryUnitMap.put("ROOM", "RM");
		secondaryUnitMap.put("SIDE", "SIDE");
		secondaryUnitMap.put("SLIP", "SLIP");
		secondaryUnitMap.put("SPACE", "SPC");
		secondaryUnitMap.put("SPC", "SPC");
		secondaryUnitMap.put("STE", "STE");
		secondaryUnitMap.put("STOP", "STOP");
		secondaryUnitMap.put("SUITE", "STE");
		secondaryUnitMap.put("TRAILER", "TRLR");
		secondaryUnitMap.put("TRLR", "TRLR");
		secondaryUnitMap.put("UNIT", "UNIT");
		secondaryUnitMap.put("UPPER", "UPPR");
		secondaryUnitMap.put("UPPR", "UPPR");
		
		streetTypeMap.put("ALLEE", "Aly");
		streetTypeMap.put("ALLEY", "Aly");
		streetTypeMap.put("ALLY", "Aly");
		streetTypeMap.put("ALY", "Aly");
		streetTypeMap.put("ANEX", "Anx");
		streetTypeMap.put("ANNEX", "Anx");
		streetTypeMap.put("ANNX", "Anx");
		streetTypeMap.put("ANX", "Anx");
		streetTypeMap.put("ARC", "Arc");
		streetTypeMap.put("ARCADE", "Arc");
		streetTypeMap.put("AV", "Ave");
		streetTypeMap.put("AVE", "Ave");
		streetTypeMap.put("AVEN", "Ave");
		streetTypeMap.put("AVENU", "Ave");
		streetTypeMap.put("AVENUE", "Ave");
		streetTypeMap.put("AVN", "Ave");
		streetTypeMap.put("AVNUE", "Ave");
		streetTypeMap.put("BAYOO", "Byu");
		streetTypeMap.put("BAYOU", "Byu");
		streetTypeMap.put("BCH", "Bch");
		streetTypeMap.put("BEACH", "Bch");
		streetTypeMap.put("BEND", "Bnd");
		streetTypeMap.put("BG", "Bg");
		streetTypeMap.put("BGS", "Bgs");
		streetTypeMap.put("BLF", "Blf");
		streetTypeMap.put("BLFS", "Blfs");
		streetTypeMap.put("BLUF", "Blf");
		streetTypeMap.put("BLUFF", "Blf");
		streetTypeMap.put("BLUFFS", "Blfs");
		streetTypeMap.put("BLVD", "Blvd");
		streetTypeMap.put("BND", "Bnd");
		streetTypeMap.put("BOT", "Btm");
		streetTypeMap.put("BOTTM", "Btm");
		streetTypeMap.put("BOTTOM", "Btm");
		streetTypeMap.put("BOUL", "Blvd");
		streetTypeMap.put("BOULEVARD", "Blvd");
		streetTypeMap.put("BOULV", "Blvd");
		streetTypeMap.put("BR", "Br");
		streetTypeMap.put("BRANCH", "Br");
		streetTypeMap.put("BRDGE", "Brg");
		streetTypeMap.put("BRG", "Brg");
		streetTypeMap.put("BRIDGE", "Brg");
		streetTypeMap.put("BRK", "Brk");
		streetTypeMap.put("BRKS", "Brks");
		streetTypeMap.put("BRNCH", "Br");
		streetTypeMap.put("BROOK", "Brk");
		streetTypeMap.put("BROOKS", "Brks");
		streetTypeMap.put("BTM", "Btm");
		streetTypeMap.put("BURG", "Bg");
		streetTypeMap.put("BURGS", "Bgs");
		streetTypeMap.put("BYP", "Byp");
		streetTypeMap.put("BYPA", "Byp");
		streetTypeMap.put("BYPAS", "Byp");
		streetTypeMap.put("BYPASS", "ByP");
		streetTypeMap.put("BYPS", "Byp");
		streetTypeMap.put("BYU", "Byu");
		streetTypeMap.put("CAM", "Cam");
		streetTypeMap.put("CAM.", "Cam");
		streetTypeMap.put("CAMINO", "Cam");
		streetTypeMap.put("CAMP", "Cp");
		streetTypeMap.put("CANYN", "Cyn");
		streetTypeMap.put("CANYON", "Cyn");
		streetTypeMap.put("CAPE", "Cpe");
		streetTypeMap.put("CAUSEWAY", "Cswy");
		streetTypeMap.put("CAUSWAY", "Cswy");
		streetTypeMap.put("CEN", "Ctr");
		streetTypeMap.put("CENT", "Ctr");
		streetTypeMap.put("CENTER", "Ctr");
		streetTypeMap.put("CENTERS", "Ctrs");
		streetTypeMap.put("CENTR", "Ctr");
		streetTypeMap.put("CENTRE", "Ctr");
		streetTypeMap.put("CIR", "Cir");
		streetTypeMap.put("CIRC", "Cir");
		streetTypeMap.put("CIRCL", "Cir");
		streetTypeMap.put("CIRCLE", "Cir");
		streetTypeMap.put("CIRCLES", "Cirs");
		streetTypeMap.put("CIRS", "Cirs");
		streetTypeMap.put("CK", "Crk");
		streetTypeMap.put("CLB", "Clb");
		streetTypeMap.put("CLF", "Clf");
		streetTypeMap.put("CLFS", "Clfs");
		streetTypeMap.put("CLIFF", "Clf");
		streetTypeMap.put("CLIFFS", "Clfs");
		streetTypeMap.put("CLUB", "Clb");
		streetTypeMap.put("CMN", "Cmn");
		streetTypeMap.put("CMP", "Cp");
		streetTypeMap.put("CNTER", "Ctr");
		streetTypeMap.put("CNTR", "Ctr");
		streetTypeMap.put("CNYN", "Cyn");
		streetTypeMap.put("CO HWY", "Co Hwy");
		streetTypeMap.put("COMMON", "Cmn");
		streetTypeMap.put("COR", "Cor");
		streetTypeMap.put("CORD", "Co Rd");
		streetTypeMap.put("CO RD", "Co Rd");
		streetTypeMap.put("CORNER", "Cor");
		streetTypeMap.put("CORNERS", "Cors");
		streetTypeMap.put("CORS", "Cors");
		streetTypeMap.put("CO RTE", "Co Rte");
		streetTypeMap.put("CO ST AID HWY", "Co St Aid Hwy");
		streetTypeMap.put("COUNTY HIGHWAY", "Co Hwy");
		streetTypeMap.put("COUNTY HIGH WAY", "Co Hwy");
		streetTypeMap.put("COUNTY HWY", "Co Hwy");
		streetTypeMap.put("COUNTY RD", "Co Rd");
		streetTypeMap.put("COUNTY ROAD", "Co Rd");
		streetTypeMap.put("COUNTY ROUTE", "Co Rte");
		streetTypeMap.put("COURSE", "Crse");
		streetTypeMap.put("COURT", "Ct");
		streetTypeMap.put("COURTS", "Cts");
		streetTypeMap.put("COVE", "Cv");
		streetTypeMap.put("COVES", "Cvs");
		streetTypeMap.put("CP", "Cp");
		streetTypeMap.put("CPE", "Cpe");
		streetTypeMap.put("CR", "Crk");
		streetTypeMap.put("CRCL", "Cir");
		streetTypeMap.put("CRCLE", "Cir");
		streetTypeMap.put("CRECENT", "Cres");
		streetTypeMap.put("CREEK", "Crk");
		streetTypeMap.put("CRES", "Cres");
		streetTypeMap.put("CRESCENT", "Cres");
		streetTypeMap.put("CRESENT", "Cres");
		streetTypeMap.put("CREST", "Crst");
		streetTypeMap.put("CRK", "Crk");
		streetTypeMap.put("CROSSING", "Xing");
		streetTypeMap.put("CROSSROAD", "Xrd");
		streetTypeMap.put("CRSCNT", "Cres");
		streetTypeMap.put("CRSE", "Crse");
		streetTypeMap.put("CRSENT", "Cres");
		streetTypeMap.put("CRSNT", "Cres");
		streetTypeMap.put("CRSSING", "Xing");
		streetTypeMap.put("CRSSNG", "Xing");
		streetTypeMap.put("CRST", "Crst");
		streetTypeMap.put("CRT", "Ct");
		streetTypeMap.put("CSWY", "Cswy");
		streetTypeMap.put("CT", "Ct");
		streetTypeMap.put("CTR", "Ctr");
		streetTypeMap.put("CTRS", "Ctrs");
		streetTypeMap.put("CTS", "Cts");
		streetTypeMap.put("CURV", "Curv");
		streetTypeMap.put("CURVE", "Curv");
		streetTypeMap.put("CV", "Cv");
		streetTypeMap.put("CVS", "Cvs");
		streetTypeMap.put("CYN", "Cyn");
		streetTypeMap.put("DALE", "Dl");
		streetTypeMap.put("DAM", "Dm");
		streetTypeMap.put("DIV", "Dv");
		streetTypeMap.put("DIVIDE", "Dv");
		streetTypeMap.put("DL", "Dl");
		streetTypeMap.put("DM", "Dm");
		streetTypeMap.put("DR", "Dr");
		streetTypeMap.put("DRIV", "Dr");
		streetTypeMap.put("DRIVE", "Dr");
		streetTypeMap.put("DRIVES", "Drs");
		streetTypeMap.put("DRS", "Drs");
		streetTypeMap.put("DRV", "Dr");
		streetTypeMap.put("DV", "Dv");
		streetTypeMap.put("DVD", "Dv");
		streetTypeMap.put("EST", "Est");
		streetTypeMap.put("ESTATE", "Est");
		streetTypeMap.put("ESTATES", "Ests");
		streetTypeMap.put("ESTS", "Ests");
		streetTypeMap.put("EXP", "Expy");
		streetTypeMap.put("EXPR", "Expy");
		streetTypeMap.put("EXPRESS", "Expy");
		streetTypeMap.put("EXPRESSWAY", "Expy");
		streetTypeMap.put("EXPW", "Expy");
		streetTypeMap.put("EXPY", "Expy");
		streetTypeMap.put("EXT", "Ext");
		streetTypeMap.put("EXTENSION", "Ext");
		streetTypeMap.put("EXTENSIONS", "Exts");
		streetTypeMap.put("EXTN", "Ext");
		streetTypeMap.put("EXTNSN", "Ext");
		streetTypeMap.put("EXTS", "Exts");
		streetTypeMap.put("FALL", "Fall");
		streetTypeMap.put("FALLS", "Fls");
		streetTypeMap.put("FARM RD", "Farm Rd");
		streetTypeMap.put("FERRY", "Fry");
		streetTypeMap.put("FIELD", "Fld");
		streetTypeMap.put("FIELDS", "Flds");
		streetTypeMap.put("FIRE RD", "Fire Rd");
		streetTypeMap.put("FLAT", "Flt");
		streetTypeMap.put("FLATS", "Flts");
		streetTypeMap.put("FLD", "Fld");
		streetTypeMap.put("FLDS", "Flds");
		streetTypeMap.put("FLS", "Fls");
		streetTypeMap.put("FLT", "Flt");
		streetTypeMap.put("FLTS", "Flts");
		streetTypeMap.put("FORD", "Frd");
		streetTypeMap.put("FORDS", "Frds");
		streetTypeMap.put("FOREST RD", "Forest Rd");
		streetTypeMap.put("FOREST ROAD", "Forest Rd");
		streetTypeMap.put("FOREST ROUTE", "Forest Rte");
		streetTypeMap.put("FOREST RTE", "Forest Rte");
		streetTypeMap.put("FORG", "Frg");
		streetTypeMap.put("FORGE", "Frg");
		streetTypeMap.put("FORGES", "Frgs");
		streetTypeMap.put("FORK", "Frk");
		streetTypeMap.put("FORKS", "Frks");
		streetTypeMap.put("FORT", "Ft");
		streetTypeMap.put("FRD", "Frd");
		streetTypeMap.put("FRDS", "Frds");
		streetTypeMap.put("FREEWAY", "Fwy");
		streetTypeMap.put("FREEWY", "Fwy");
		streetTypeMap.put("FRG", "Frg");
		streetTypeMap.put("FRGS", "Frgs");
		streetTypeMap.put("FRK", "Frk");
		streetTypeMap.put("FRKS", "Frks");
		streetTypeMap.put("FRRY", "Fry");
		streetTypeMap.put("FRT", "Ft");
		streetTypeMap.put("FRWAY", "Fwy");
		streetTypeMap.put("FRWY", "Fwy");
		streetTypeMap.put("FRY", "Fry");
		streetTypeMap.put("FT", "Ft");
		streetTypeMap.put("FWY", "Fwy");
		streetTypeMap.put("GARDEN", "Gdn");
		streetTypeMap.put("GARDENS", "Gdns");
		streetTypeMap.put("GARDN", "Gdn");
		streetTypeMap.put("GATEWAY", "Gtwy");
		streetTypeMap.put("GATEWY", "Gtwy");
		streetTypeMap.put("GATWAY", "Gtwy");
		streetTypeMap.put("GDN", "Gdn");
		streetTypeMap.put("GDNS", "Gdns");
		streetTypeMap.put("GLEN", "Gln");
		streetTypeMap.put("GLENS", "Glns");
		streetTypeMap.put("GLN", "Gln");
		streetTypeMap.put("GLNS", "Glns");
		streetTypeMap.put("GRDEN", "Gdn");
		streetTypeMap.put("GRDN", "Gdn");
		streetTypeMap.put("GRDNS", "Gdns");
		streetTypeMap.put("GREEN", "Grn");
		streetTypeMap.put("GREENS", "Grns");
		streetTypeMap.put("GRN", "Grn");
		streetTypeMap.put("GRNS", "Grns");
		streetTypeMap.put("GROV", "Grv");
		streetTypeMap.put("GROVE", "Grv");
		streetTypeMap.put("GROVES", "Grvs");
		streetTypeMap.put("GRV", "Grv");
		streetTypeMap.put("GRVS", "Grvs");
		streetTypeMap.put("GTWAY", "Gtwy");
		streetTypeMap.put("GTWY", "Gtwy");
		streetTypeMap.put("HARB", "Hbr");
		streetTypeMap.put("HARBOR", "Hbr");
		streetTypeMap.put("HARBORS", "Hbrs");
		streetTypeMap.put("HARBR", "Hbr");
		streetTypeMap.put("HAVEN", "Hvn");
		streetTypeMap.put("HAVN", "Hvn");
		streetTypeMap.put("HBR", "Hbr");
		streetTypeMap.put("HBRS", "Hbrs");
		streetTypeMap.put("HEIGHT", "Hts");
		streetTypeMap.put("HEIGHTS", "Hts");
		streetTypeMap.put("HGTS", "Hts");
		streetTypeMap.put("HIGHWAY", "Hwy");
		streetTypeMap.put("HIGHWY", "Hwy");
		streetTypeMap.put("HILL", "Hl");
		streetTypeMap.put("HILLS", "Hls");
		streetTypeMap.put("HIWAY", "Hwy");
		streetTypeMap.put("HIWY", "Hwy");
		streetTypeMap.put("HL", "Hl");
		streetTypeMap.put("HLLW", "Holw");
		streetTypeMap.put("HLS", "Hls");
		streetTypeMap.put("HOLLOW", "Holw");
		streetTypeMap.put("HOLLOWS", "Holw");
		streetTypeMap.put("HOLW", "Holw");
		streetTypeMap.put("HOLWS", "Holw");
		streetTypeMap.put("HRBOR", "Hbr");
		streetTypeMap.put("HT", "Hts");
		streetTypeMap.put("HTS", "Hts");
		streetTypeMap.put("HVN", "Hvn");
		streetTypeMap.put("HWAY", "Hwy");
		streetTypeMap.put("HWY", "Hwy");
		streetTypeMap.put("I", "I-");
		streetTypeMap.put("I-", "I-");
		streetTypeMap.put("INLET", "Inlt");
		streetTypeMap.put("INLT", "Inlt");
		streetTypeMap.put("INTERSTATE", "I-");
		streetTypeMap.put("INTERSTATE ROUTE", "I-");
		streetTypeMap.put("INTERSTATE RT", "I-");
		streetTypeMap.put("INTERSTATE RTE", "I-");
		streetTypeMap.put("INTERSTATE RTE.", "I-");
		streetTypeMap.put("IS", "Is");
		streetTypeMap.put("ISLAND", "Is");
		streetTypeMap.put("ISLANDS", "Iss");
		streetTypeMap.put("ISLE", "Isle");
		streetTypeMap.put("ISLES", "Isle");
		streetTypeMap.put("ISLND", "Is");
		streetTypeMap.put("ISLNDS", "Iss");
		streetTypeMap.put("ISS", "Iss");
		streetTypeMap.put("JCT", "Jct");
		streetTypeMap.put("JCTION", "Jct");
		streetTypeMap.put("JCTN", "Jct");
		streetTypeMap.put("JCTNS", "Jcts");
		streetTypeMap.put("JCTS", "Jcts");
		streetTypeMap.put("JUNCTION", "Jct");
		streetTypeMap.put("JUNCTIONS", "Jcts");
		streetTypeMap.put("JUNCTN", "Jct");
		streetTypeMap.put("JUNCTON", "Jct");
		streetTypeMap.put("KEY", "Ky");
		streetTypeMap.put("KEYS", "Kys");
		streetTypeMap.put("KNL", "Knl");
		streetTypeMap.put("KNLS", "Knls");
		streetTypeMap.put("KNOL", "Knl");
		streetTypeMap.put("KNOLL", "Knl");
		streetTypeMap.put("KNOLLS", "Knls");
		streetTypeMap.put("KY", "Ky");
		streetTypeMap.put("KYS", "Kys");
		streetTypeMap.put("LA", "Ln");
		streetTypeMap.put("LAKE", "Lk");
		streetTypeMap.put("LAKES", "Lks");
		streetTypeMap.put("LAND", "Land");
		streetTypeMap.put("LANDING", "Lndg");
		streetTypeMap.put("LANE", "Ln");
		streetTypeMap.put("LANES", "Ln");
		streetTypeMap.put("LCK", "Lck");
		streetTypeMap.put("LCKS", "Lcks");
		streetTypeMap.put("LDG", "Ldg");
		streetTypeMap.put("LDGE", "Ldg");
		streetTypeMap.put("LF", "Lf");
		streetTypeMap.put("LGT", "Lgt");
		streetTypeMap.put("LGTS", "Lgts");
		streetTypeMap.put("LIGHT", "Lgt");
		streetTypeMap.put("LIGHTS", "Lgts");
		streetTypeMap.put("LK", "Lk");
		streetTypeMap.put("LKS", "Lks");
		streetTypeMap.put("LN", "Ln");
		streetTypeMap.put("LNDG", "Lndg");
		streetTypeMap.put("LNDNG", "Lndg");
		streetTypeMap.put("LOAF", "Lf");
		streetTypeMap.put("LOCK", "Lck");
		streetTypeMap.put("LOCKS", "Lcks");
		streetTypeMap.put("LODG", "Ldg");
		streetTypeMap.put("LODGE", "Ldg");
		streetTypeMap.put("LOOP", "Loop");
		streetTypeMap.put("LOOPS", "Loop");
		streetTypeMap.put("MALL", "Mall");
		streetTypeMap.put("MANOR", "Mnr");
		streetTypeMap.put("MANORS", "Mnrs");
		streetTypeMap.put("MDW", "Mdw");
		streetTypeMap.put("MDWS", "Mdws");
		streetTypeMap.put("MEADOW", "Mdw");
		streetTypeMap.put("MEADOWS", "Mdws");
		streetTypeMap.put("MEDOWS", "Mdws");
		streetTypeMap.put("MEWS", "Mews");
		streetTypeMap.put("MILL", "Ml");
		streetTypeMap.put("MILLS", "Mls");
		streetTypeMap.put("MISSION", "Msn");
		streetTypeMap.put("MISSN", "Msn");
		streetTypeMap.put("ML", "Ml");
		streetTypeMap.put("MLS", "Mls");
		streetTypeMap.put("MNR", "Mnr");
		streetTypeMap.put("MNRS", "Mnrs");
		streetTypeMap.put("MNT", "Mt");
		streetTypeMap.put("MNTAIN", "Mtn");
		streetTypeMap.put("MNTN", "Mtn");
		streetTypeMap.put("MNTNS", "Mtns");
		streetTypeMap.put("MOTORWAY", "Mtwy");
		streetTypeMap.put("MOUNT", "Mt");
		streetTypeMap.put("MOUNTAIN", "Mtn");
		streetTypeMap.put("MOUNTAINS", "Mtns");
		streetTypeMap.put("MOUNTIN", "Mtn");
		streetTypeMap.put("MSN", "Msn");
		streetTypeMap.put("MSSN", "Msn");
		streetTypeMap.put("MT", "Mt");
		streetTypeMap.put("MTIN", "Mtn");
		streetTypeMap.put("MTN", "Mtn");
		streetTypeMap.put("MTNS", "Mtns");
		streetTypeMap.put("MTWY", "Mtwy");
		streetTypeMap.put("NCK", "Nck");
		streetTypeMap.put("NECK", "Nck");
		streetTypeMap.put("OPAS", "Opas");
		streetTypeMap.put("ORCH", "Orch");
		streetTypeMap.put("ORCHARD", "Orch");
		streetTypeMap.put("ORCHRD", "Orch");
		streetTypeMap.put("OVAL", "Oval");
		streetTypeMap.put("OVERPASS", "Opas");
		streetTypeMap.put("OVL", "Oval");
		streetTypeMap.put("PARK", "Park");
		streetTypeMap.put("PARKS", "Park");
		streetTypeMap.put("PARKWAY", "Pkwy");
		streetTypeMap.put("PARKWAYS", "Pkwy");
		streetTypeMap.put("PARKWY", "Pkwy");
		streetTypeMap.put("PASS", "Pass");
		streetTypeMap.put("PASSAGE", "Psge");
		streetTypeMap.put("PATH", "Path");
		streetTypeMap.put("PATHS", "Path");
		streetTypeMap.put("PIKE", "Pike");
		streetTypeMap.put("PIKES", "Pike");
		streetTypeMap.put("PINE", "Pne");
		streetTypeMap.put("PINES", "Pnes");
		streetTypeMap.put("PK", "Park");
		streetTypeMap.put("PKWAY", "Pkwy");
		streetTypeMap.put("PKWY", "Pkwy");
		streetTypeMap.put("PKWYS", "Pkwy");
		streetTypeMap.put("PKY", "Pkwy");
		streetTypeMap.put("PL", "Pl");
		streetTypeMap.put("PLACE", "Pl");
		streetTypeMap.put("PLAIN", "Pln");
		streetTypeMap.put("PLAINES", "Plns");
		streetTypeMap.put("PLAINS", "Plns");
		streetTypeMap.put("PLAZA", "Plz");
		streetTypeMap.put("PLN", "Pln");
		streetTypeMap.put("PLNS", "Plns");
		streetTypeMap.put("PLZ", "Plz");
		streetTypeMap.put("PLZA", "Plz");
		streetTypeMap.put("PNE", "Pne");
		streetTypeMap.put("PNES", "Pnes");
		streetTypeMap.put("POINT", "Pt");
		streetTypeMap.put("POINTS", "Pts");
		streetTypeMap.put("PORT", "Prt");
		streetTypeMap.put("PORTS", "Prts");
		streetTypeMap.put("PR", "Pr");
		streetTypeMap.put("PRAIRIE", "Pr");
		streetTypeMap.put("PRARIE", "Pr");
		streetTypeMap.put("PRK", "Park");
		streetTypeMap.put("PRR", "Pr");
		streetTypeMap.put("PRT", "Prt");
		streetTypeMap.put("PRTS", "Prts");
		streetTypeMap.put("PSGE", "Psge");
		streetTypeMap.put("PT", "Pt");
		streetTypeMap.put("PTS", "Pts");
		streetTypeMap.put("RAD", "Radl");
		streetTypeMap.put("RADIAL", "Radl");
		streetTypeMap.put("RADIEL", "Radl");
		streetTypeMap.put("RADL", "Radl");
		streetTypeMap.put("RAMP", "Ramp");
		streetTypeMap.put("RANCH", "Rnch");
		streetTypeMap.put("RANCHES", "Rnch");
		streetTypeMap.put("RAPID", "Rpd");
		streetTypeMap.put("RAPIDS", "Rpds");
		streetTypeMap.put("RD", "Rd");
		streetTypeMap.put("RDG", "Rdg");
		streetTypeMap.put("RDGE", "Rdg");
		streetTypeMap.put("RDGS", "Rdgs");
		streetTypeMap.put("RDS", "Rds");
		streetTypeMap.put("REST", "Rst");
		streetTypeMap.put("RIDGE", "Rdg");
		streetTypeMap.put("RIDGES", "Rdgs");
		streetTypeMap.put("RIV", "Riv");
		streetTypeMap.put("RIVER", "Riv");
		streetTypeMap.put("RIVR", "Riv");
		streetTypeMap.put("RNCH", "Rnch");
		streetTypeMap.put("RNCHS", "Rnch");
		streetTypeMap.put("ROAD", "Rd");
		streetTypeMap.put("ROADS", "Rds");
		streetTypeMap.put("ROUTE", "Rte");
		streetTypeMap.put("ROW", "Row");
		streetTypeMap.put("RPD", "Rpd");
		streetTypeMap.put("RPDS", "Rpds");
		streetTypeMap.put("RST", "Rst");
		streetTypeMap.put("RT", "Rte");
		streetTypeMap.put("RTE", "Rte");
		streetTypeMap.put("RUE", "Rue");
		streetTypeMap.put("RUN", "Run");
		streetTypeMap.put("RVR", "Riv");
		streetTypeMap.put("SERVICE DR", "Svc Dr");
		streetTypeMap.put("SERVICE DRIVE", "Svc Dr");
		streetTypeMap.put("SERVICE RD", "Svc Rd");
		streetTypeMap.put("SERVICE ROAD", "Svc Rd");
		streetTypeMap.put("SHL", "Shl");
		streetTypeMap.put("SHLS", "Shls");
		streetTypeMap.put("SHOAL", "Shl");
		streetTypeMap.put("SHOALS", "Shls");
		streetTypeMap.put("SHOAR", "Shr");
		streetTypeMap.put("SHOARS", "Shrs");
		streetTypeMap.put("SHORE", "Shr");
		streetTypeMap.put("SHORES", "Shrs");
		streetTypeMap.put("SHR", "Shr");
		streetTypeMap.put("SHRS", "Shrs");
		streetTypeMap.put("SKWY", "Skwy");
		streetTypeMap.put("SKYWAY", "Skwy");
		streetTypeMap.put("SMT", "Smt");
		streetTypeMap.put("SPG", "Spg");
		streetTypeMap.put("SPGS", "Spgs");
		streetTypeMap.put("SPNG", "Spg");
		streetTypeMap.put("SPNGS", "Spgs");
		streetTypeMap.put("SPRING", "Spg");
		streetTypeMap.put("SPRINGS", "Spgs");
		streetTypeMap.put("SPRNG", "Spg");
		streetTypeMap.put("SPRNGS", "Spgs");
		streetTypeMap.put("SPUR", "Spur");
		streetTypeMap.put("SPURS", "Spur");
		streetTypeMap.put("SQ", "Sq");
		streetTypeMap.put("SQR", "Sq");
		streetTypeMap.put("SQRE", "Sq");
		streetTypeMap.put("SQRS", "Sqs");
		streetTypeMap.put("SQS", "Sqs");
		streetTypeMap.put("SQU", "Sq");
		streetTypeMap.put("SQUARE", "Sq");
		streetTypeMap.put("SQUARES", "Sqs");
		streetTypeMap.put("ST", "St");
		streetTypeMap.put("STA", "Sta");
		streetTypeMap.put("STATE HIGHWAY", "State Hwy");
		streetTypeMap.put("STATE HIGH WAY", "State Hwy");
		streetTypeMap.put("STATE HWY", "State Hwy");
		streetTypeMap.put("STATE RD", "State Rd");
		streetTypeMap.put("STATE ROAD", "State Rd");
		streetTypeMap.put("STATE ROUTE", "State Rte");
		streetTypeMap.put("STATE RTE", "State Rte");
		streetTypeMap.put("STATION", "Sta");
		streetTypeMap.put("STATN", "Sta");
		streetTypeMap.put("STN", "Sta");
		streetTypeMap.put("STR", "St");
		streetTypeMap.put("STRA", "Stra");
		streetTypeMap.put("STRAV", "Stra");
		streetTypeMap.put("STRAVE", "Stra");
		streetTypeMap.put("STRAVEN", "Stra");
		streetTypeMap.put("STRAVENUE", "Stra");
		streetTypeMap.put("STRAVN", "Stra");
		streetTypeMap.put("STREAM", "Strm");
		streetTypeMap.put("STREET", "St");
		streetTypeMap.put("STREETS", "Sts");
		streetTypeMap.put("STREME", "Strm");
		streetTypeMap.put("STRM", "Strm");
		streetTypeMap.put("STRT", "St");
		streetTypeMap.put("STRVN", "Stra");
		streetTypeMap.put("STRVNUE", "Stra");
		streetTypeMap.put("STS", "Sts");
		streetTypeMap.put("SUMIT", "Smt");
		streetTypeMap.put("SUMITT", "Smt");
		streetTypeMap.put("SUMMIT", "Smt");
		streetTypeMap.put("TER", "Ter");
		streetTypeMap.put("TERR", "Ter");
		streetTypeMap.put("TERRACE", "Ter");
		streetTypeMap.put("THROUGHWAY", "Trwy");
		streetTypeMap.put("TPK", "Tpke");
		streetTypeMap.put("TPKE", "Tpke");
		streetTypeMap.put("TR", "Trl");
		streetTypeMap.put("TRACE", "Trce");
		streetTypeMap.put("TRACES", "Trce");
		streetTypeMap.put("TRACK", "Trak");
		streetTypeMap.put("TRACKS", "Trak");
		streetTypeMap.put("TRAFFICWAY", "Trfy");
		streetTypeMap.put("TRAIL", "Trl");
		streetTypeMap.put("TRAILS", "Trl");
		streetTypeMap.put("TRAK", "Trak");
		streetTypeMap.put("TRCE", "Trce");
		streetTypeMap.put("TRFY", "Trfy");
		streetTypeMap.put("TRK", "Trak");
		streetTypeMap.put("TRKS", "Trak");
		streetTypeMap.put("TRL", "Trl");
		streetTypeMap.put("TRLS", "Trl");
		streetTypeMap.put("TRNPK", "Tpke");
		streetTypeMap.put("TRPK", "Tpke");
		streetTypeMap.put("TRWY", "Trwy");
		streetTypeMap.put("TUNEL", "Tunl");
		streetTypeMap.put("TUNL", "Tunl");
		streetTypeMap.put("TUNLS", "Tunl");
		streetTypeMap.put("TUNNEL", "Tunl");
		streetTypeMap.put("TUNNELS", "Tunl");
		streetTypeMap.put("TUNNL", "Tunl");
		streetTypeMap.put("TURNPIKE", "Tpke");
		streetTypeMap.put("TURNPK", "Tpke");
		streetTypeMap.put("UN", "Un");
		streetTypeMap.put("UNDERPASS", "Upas");
		streetTypeMap.put("UNION", "Un");
		streetTypeMap.put("UNIONS", "Uns");
		streetTypeMap.put("UNS", "Uns");
		streetTypeMap.put("UPAS", "Upas");
		streetTypeMap.put("U.S.", "US Hwy");
		streetTypeMap.put("USFS HIGHWAY", "USFS Hwy");
		streetTypeMap.put("USFS HIGH WAY", "USFS Hwy");
		streetTypeMap.put("USFS HWY", "USFS Hwy");
		streetTypeMap.put("USFS RD", "USFS Rd");
		streetTypeMap.put("USFS ROAD", "USFS Rd");
		streetTypeMap.put("US HIGHWAY", "US Hwy");
		streetTypeMap.put("US HIGH WAY", "US Hwy");
		streetTypeMap.put("US HWY", "US Hwy");
		streetTypeMap.put("US ROUTE", "US Rte");
		streetTypeMap.put("US RT", "US Rte");
		streetTypeMap.put("US RTE", "US Rte");
		streetTypeMap.put("VALLEY", "Vly");
		streetTypeMap.put("VALLEYS", "Vlys");
		streetTypeMap.put("VALLY", "Vly");
		streetTypeMap.put("VDCT", "Via");
		streetTypeMap.put("VIA", "Via");
		streetTypeMap.put("VIADCT", "Via");
		streetTypeMap.put("VIADUCT", "Via");
		streetTypeMap.put("VIEW", "Vw");
		streetTypeMap.put("VIEWS", "Vws");
		streetTypeMap.put("VILL", "Vlg");
		streetTypeMap.put("VILLAG", "Vlg");
		streetTypeMap.put("VILLAGE", "Vlg");
		streetTypeMap.put("VILLAGES", "Vlgs");
		streetTypeMap.put("VILLE", "Vl");
		streetTypeMap.put("VILLG", "Vlg");
		streetTypeMap.put("VILLIAGE", "Vlg");
		streetTypeMap.put("VIS", "Vis");
		streetTypeMap.put("VIST", "Vis");
		streetTypeMap.put("VISTA", "Vis");
		streetTypeMap.put("VL", "Vl");
		streetTypeMap.put("VLG", "Vlg");
		streetTypeMap.put("VLGS", "Vlgs");
		streetTypeMap.put("VLLY", "Vly");
		streetTypeMap.put("VLY", "Vly");
		streetTypeMap.put("VLYS", "Vlys");
		streetTypeMap.put("VST", "Vis");
		streetTypeMap.put("VSTA", "Vis");
		streetTypeMap.put("VW", "Vw");
		streetTypeMap.put("VWS", "Vws");
		streetTypeMap.put("WALK", "Walk");
		streetTypeMap.put("WALKS", "Walk");
		streetTypeMap.put("WALL", "Wall");
		streetTypeMap.put("WAY", "Way");
		streetTypeMap.put("WAYS", "Ways");
		streetTypeMap.put("WELL", "Wl");
		streetTypeMap.put("WELLS", "Wls");
		streetTypeMap.put("WL", "Wl");
		streetTypeMap.put("WLS", "Wls");
		streetTypeMap.put("WY", "Way");
		streetTypeMap.put("XING", "Xing");
		streetTypeMap.put("XRD", "Xrd");

		beforeStreetTypeMap.put("AV", "Ave");
		beforeStreetTypeMap.put("AVE", "Ave");
		beforeStreetTypeMap.put("AVEN", "Ave");
		beforeStreetTypeMap.put("AVENU", "Ave");
		beforeStreetTypeMap.put("AVENUE", "Ave");
		beforeStreetTypeMap.put("AVN", "Ave");
		beforeStreetTypeMap.put("AVNUE", "Ave");
		beforeStreetTypeMap.put("CO RTE", "Co Rte");
		beforeStreetTypeMap.put("CO ST AID HWY", "Co St Aid Hwy");
		beforeStreetTypeMap.put("COUNTY HIGHWAY", "Co Hwy");
		beforeStreetTypeMap.put("COUNTY HIGH WAY", "Co Hwy");
		beforeStreetTypeMap.put("COUNTY HWY", "Co Hwy");
		beforeStreetTypeMap.put("COUNTY RD", "Co Rd");
		beforeStreetTypeMap.put("COUNTY ROAD", "Co Rd");
		beforeStreetTypeMap.put("COUNTY ROUTE", "Co Rte");
		beforeStreetTypeMap.put("FOREST RD", "Forest Rd");
		beforeStreetTypeMap.put("FOREST ROAD", "Forest Rd");
		beforeStreetTypeMap.put("FOREST ROUTE", "Forest Rte");
		beforeStreetTypeMap.put("FOREST RTE", "Forest Rte");
		beforeStreetTypeMap.put("HIGHWAY", "Hwy");
		beforeStreetTypeMap.put("HIGHWY", "Hwy");
		beforeStreetTypeMap.put("HWAY", "Hwy");
		beforeStreetTypeMap.put("HWY", "Hwy");
		beforeStreetTypeMap.put("I", "I-");
		beforeStreetTypeMap.put("I-", "I-");
		beforeStreetTypeMap.put("INLET", "Inlt");
		beforeStreetTypeMap.put("INLT", "Inlt");
		beforeStreetTypeMap.put("INTERSTATE", "I-");
		beforeStreetTypeMap.put("INTERSTATE ROUTE", "I-");
		beforeStreetTypeMap.put("INTERSTATE RT", "I-");
		beforeStreetTypeMap.put("INTERSTATE RTE", "I-");
		beforeStreetTypeMap.put("INTERSTATE RTE.", "I-");
		beforeStreetTypeMap.put("LOOP", "Loop");
		beforeStreetTypeMap.put("LOOPS", "Loop");
		beforeStreetTypeMap.put("STATE HIGHWAY", "State Hwy");
		beforeStreetTypeMap.put("STATE HIGH WAY", "State Hwy");
		beforeStreetTypeMap.put("STATE HWY", "State Hwy");
		beforeStreetTypeMap.put("STATE RD", "State Rd");
		beforeStreetTypeMap.put("STATE ROAD", "State Rd");
		beforeStreetTypeMap.put("STATE ROUTE", "State Rte");
		beforeStreetTypeMap.put("STATE RTE", "State Rte");
		beforeStreetTypeMap.put("USFS HIGHWAY", "USFS Hwy");
		beforeStreetTypeMap.put("USFS HIGH WAY", "USFS Hwy");
		beforeStreetTypeMap.put("USFS HWY", "USFS Hwy");
		beforeStreetTypeMap.put("USFS RD", "USFS Rd");
		beforeStreetTypeMap.put("USFS ROAD", "USFS Rd");
		beforeStreetTypeMap.put("US HIGHWAY", "US Hwy");
		beforeStreetTypeMap.put("US HIGH WAY", "US Hwy");
		beforeStreetTypeMap.put("US HWY", "US Hwy");
		beforeStreetTypeMap.put("US ROUTE", "US Rte");
		beforeStreetTypeMap.put("US RT", "US Rte");
		beforeStreetTypeMap.put("US RTE", "US Rte");

		streetDirectionMap.put("E", "E");
		streetDirectionMap.put("EAST", "E");
		streetDirectionMap.put("N", "N");
		streetDirectionMap.put("NE", "NE");
		streetDirectionMap.put("NORTH", "N");
		streetDirectionMap.put("NORTHEAST", "NE");
		streetDirectionMap.put("NORTH EAST", "NE");
		streetDirectionMap.put("NORTH_EAST", "NE");
		streetDirectionMap.put("NORTH-EAST", "NE");
		streetDirectionMap.put("NORTHWEST", "NW");
		streetDirectionMap.put("NORTH WEST", "NW");
		streetDirectionMap.put("NORTH_WEST", "NW");
		streetDirectionMap.put("NORTH-WEST", "NW");
		streetDirectionMap.put("NW", "NW");
		streetDirectionMap.put("S", "S");
		streetDirectionMap.put("SE", "SE");
		streetDirectionMap.put("SOUTH", "S");
		streetDirectionMap.put("SOUTHEAST", "SE");
		streetDirectionMap.put("SOUTH EAST", "SE");
		streetDirectionMap.put("SOUTH_EAST", "SE");
		streetDirectionMap.put("SOUTH-EAST", "SE");
		streetDirectionMap.put("SOUTHWEST", "SW");
		streetDirectionMap.put("SOUTH WEST", "SW");
		streetDirectionMap.put("SOUTH_WEST", "SW");
		streetDirectionMap.put("SOUTH-WEST", "SW");
		streetDirectionMap.put("SW", "SW");
		streetDirectionMap.put("W", "W");
		streetDirectionMap.put("WEST", "W");

	}

	public void parse(Address address) {
		logger.info("Address Line 1: " + address.getAddressLine1());
		String[] fields = address.getAddressLine1().replaceAll("\\.", "").toUpperCase().trim().split("[ ,-]+");
		
		// check if street direction attached street number.
		Pattern p = Pattern.compile("[A-Z]+$");
		Matcher m = p.matcher(fields[0]);
		if(m.find()){
			String [] newFields = new String[fields.length +1];
			if(streetDirectionMap.get(m.group()) != null){
				for(int i = fields.length-1; i > 0; i--){
					newFields[i+1] = fields[i];
				}
				newFields[1] = m.group();
				newFields[0] = fields[0].substring(0, m.start());
				fields = newFields;
			}
		}

		int streetTypePos = -1;
		int streetTypeRange = -1;
		String streetType = null;
		String streetTypeNormalized = null;
		int secondaryUnitPos = -1;
		String secondaryUnit = null;
		
		int preStreetDirectionPos = -1; 
		String preStreetDirection = null;
		String preStreetDirectionNormalized = null;
		int preStreetDirectionRange = -1;
		int postStreetDirectionPos = -1;
		String postStreetDirection = null;
		String postStreetDirectionNormalized = null;
		int postStreetDirectionRange = -1;
		StringBuilder sb = new StringBuilder();
		
		address.setStreetNumber(fields[0]);
		address.setStreetTypeBehind(true);
		// First check street type
		for(int i = 1; i < fields.length; i++){
			if((i+1) < fields.length){
				if(streetTypeMap.get(fields[i] + " " + fields[i+1]) != null){
					streetTypePos = i;
					streetType = fields[i] + " " + fields[i+1];
					streetTypeNormalized = streetTypeMap.get(fields[i] + " " + fields[i+1]);
					streetTypeRange = 2;
					i++;
				}else if(streetTypeMap.get(fields[i]) != null){
					streetTypePos = i;
					streetType = fields[i];
					streetTypeNormalized = streetTypeMap.get(fields[i]);
					streetTypeRange = 1;
				}
			}else{
				if(streetTypeMap.get(fields[i]) != null){
					streetTypePos = i;
					streetType = fields[i];
					streetTypeNormalized = streetTypeMap.get(fields[i]);
					streetTypeRange = 1;
				}
			}
		}
		
		if(streetTypePos > 0){
			// check pre street direction
			for(int i =1; i < streetTypePos; i++){
				if((i+3) < fields.length){
					if(streetDirectionMap.get(fields[i] + " " + fields[i+1] + " " + fields[i+2] + " " + fields[i+3]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1] + " " + fields[i+2] + " " + fields[i+3];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 4;
					}else if(streetDirectionMap.get(fields[i] + " " + fields[i+1] + " " + fields[i+2]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1] + " " + fields[i+2];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 3;
					}else if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 2;
					}else if(streetDirectionMap.get(fields[i]) != null){
						if(streetDirectionMap.get(fields[i]) != null){
							preStreetDirectionPos = i;
							preStreetDirection = fields[i];
							preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
							preStreetDirectionRange = 1;
						}
					}
				}else if((i+2) < fields.length){
					if(streetDirectionMap.get(fields[i] + " " + fields[i+1] + " " + fields[i+2]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1] + " " + fields[i+2];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 3;
					}else if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 2;
					}else if(streetDirectionMap.get(fields[i]) != null){
						if(streetDirectionMap.get(fields[i]) != null){
							preStreetDirectionPos = i;
							preStreetDirection = fields[i];
							preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
							preStreetDirectionRange = 1;
						}
					}
				}else if((i+1) < fields.length){
					if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 2;
					}else if(streetDirectionMap.get(fields[i]) != null){
						if(streetDirectionMap.get(fields[i]) != null){
							preStreetDirectionPos = i;
							preStreetDirection = fields[i];
							preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
							preStreetDirectionRange = 1;
						}
					}
				}else{
					if(streetDirectionMap.get(fields[i]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 1;
					}
				}
			}
			if(preStreetDirectionPos > 0){
				if(streetTypePos == preStreetDirectionPos + preStreetDirectionRange){
					if(beforeStreetTypeMap.get(streetType) == null){
						streetTypePos = -1;
						streetTypeRange = 0;
						streetType = null;
						streetTypeNormalized = null;
					}
				}
			}else{
				if(streetTypePos == 1){
					if(beforeStreetTypeMap.get(streetType) == null){
						streetTypePos = -1;
						streetTypeRange = 0;
						streetTypeNormalized = null;
						streetType = null;
					}
				}
			}
		}

		if(streetTypePos > 0){
			// Street type is the last string
			if(streetTypePos + streetTypeRange <= fields.length){
				for(int i = streetTypePos + streetTypeRange; i < fields.length; i++){
					// First check street direction
					if((i+1) < fields.length){
						if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
							postStreetDirectionPos = i;
							postStreetDirection = fields[i] + " " + fields[i+1];
							postStreetDirectionNormalized = streetDirectionMap.get(postStreetDirection);
							postStreetDirectionRange = 2;
						}else if(streetDirectionMap.get(fields[i]) != null){
							postStreetDirectionPos = i;
							postStreetDirection = fields[i];
							postStreetDirectionNormalized = streetDirectionMap.get(postStreetDirection);
							postStreetDirectionRange = 1;
						}
					}else{
						if(streetDirectionMap.get(fields[i]) != null){
							postStreetDirectionPos = i;
							postStreetDirection = fields[i];
							postStreetDirectionNormalized = streetDirectionMap.get(postStreetDirection);
							postStreetDirectionRange = 1;
						}
					}
				}
				if(postStreetDirectionPos > 0){
					if((postStreetDirectionPos + postStreetDirectionRange) <= fields.length){
						for(int i = postStreetDirectionPos + postStreetDirectionRange; i < fields.length; i++){
							// Check secondary unit
							if(secondaryUnitMap.get(fields[i]) != null){
								secondaryUnitPos = i;
								secondaryUnit= fields[i];
							}
						} 
					}
				}else{
					for(int i = streetTypePos + streetTypeRange; i < fields.length; i++){
						// Check secondary unit
						if(secondaryUnitMap.get(fields[i]) != null){
							secondaryUnitPos = i;
							secondaryUnit= fields[i];
						}
					} 
					
				}
			}
			
			// Check pre street direction
			for(int i = 1; i < streetTypePos; i++){
				if((i+1) < fields.length){
					if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 2;
					}else if(streetDirectionMap.get(fields[i]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 1;
					}
				}else{
					if(streetDirectionMap.get(fields[i]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i];
						preStreetDirectionNormalized = streetDirectionMap.get(preStreetDirection);
						preStreetDirectionRange = 1;
					}
				}
			}
			address.setStreetType(streetTypeNormalized);
			if(preStreetDirectionPos > 0){
				if(preStreetDirectionPos != 1){
					logger.error("Don't understand this address!");
					return ;
				}
				address.setPreDir(preStreetDirectionNormalized);
				// 500 SE Hwy 50
				if(streetTypePos == preStreetDirectionPos + preStreetDirectionRange){
					address.setStreetTypeBehind(false);
					if(postStreetDirectionPos > 0){
						for(int i = streetTypePos + streetTypeRange; i < postStreetDirectionPos-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[postStreetDirectionPos-1]);
					}else if(secondaryUnitPos > 0){
						if(secondaryUnitPos == fields.length-1){
							for(int i = streetTypePos + streetTypeRange; i < secondaryUnitPos-2; i++){
								sb.append(fields[i]);
								sb.append(" ");
							}
							sb.append(fields[secondaryUnitPos-2]);
						}else{
							for(int i = streetTypePos + streetTypeRange; i < secondaryUnitPos-1; i++){
								sb.append(fields[i]);
								sb.append(" ");
							}
							sb.append(fields[secondaryUnitPos-1]);
						}
					}else{
						for(int i = streetTypePos + streetTypeRange; i < fields.length-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[fields.length-1]);
					}
				}else{
					for(int i = preStreetDirectionPos + preStreetDirectionRange; i < streetTypePos-1; i++){
						sb.append(fields[i]);
						sb.append(" ");
					}
					sb.append(fields[streetTypePos-1]);
				}
				address.setPreDir(preStreetDirectionNormalized);
				address.setStreetName(sb.toString());
				
				if(postStreetDirectionPos > 0){
					address.setPostDir(postStreetDirectionNormalized);
				}

			}else{ // No pre street direction
				if(streetTypePos == 1){// 500 Hwy 50
					address.setStreetTypeBehind(false);
					if(postStreetDirectionPos > 0){
						for(int i = streetTypePos + streetTypeRange; i < postStreetDirectionPos-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[postStreetDirectionPos-1]);
					}else if(secondaryUnitPos > 0){
						if(secondaryUnitPos == fields.length-1){
							for(int i = streetTypePos + streetTypeRange; i < secondaryUnitPos-2; i++){
								sb.append(fields[i]);
								sb.append(" ");
							}
							sb.append(fields[secondaryUnitPos-2]);
						}else{
							for(int i = streetTypePos + streetTypeRange; i < secondaryUnitPos-1; i++){
								sb.append(fields[i]);
								sb.append(" ");
							}
							sb.append(fields[secondaryUnitPos-1]);
						}
					}else{
						for(int i = streetTypePos + streetTypeRange; i < fields.length-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[fields.length-1]);
					}
				}else{ // 472 Lynette ST
					for(int i = 1; i < streetTypePos-1; i++){
						sb.append(fields[i]);
						sb.append(" ");
					}
					sb.append(fields[streetTypePos-1]);
				}
				if(postStreetDirectionPos > 0){
					address.setPostDir(postStreetDirectionNormalized);
				}
			}
		}else{
			// check pre street direction
			for(int i =1; i < 3; i++){
				if((i+1) < fields.length){
					if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i] + " " + fields[i+1];
						preStreetDirectionRange = 2;
					}else if(streetDirectionMap.get(fields[i]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i];
						preStreetDirectionRange = 1;
					}
				}else{
					if(streetDirectionMap.get(fields[i]) != null){
						preStreetDirectionPos = i;
						preStreetDirection = fields[i];
						preStreetDirectionRange = 1;
					}
				}
			}
			
			//check post street direction
			for(int i =1; i < 3; i++){
				if((i+1) < fields.length){
					if(streetDirectionMap.get(fields[i] + " " + fields[i+1]) != null){
						postStreetDirectionPos = i;
						postStreetDirection = fields[i] + " " + fields[i+1];
						postStreetDirectionRange = 2;
					}else if(streetDirectionMap.get(fields[i]) != null){
						postStreetDirectionPos = i;
						postStreetDirection = fields[i];
						postStreetDirectionRange = 1;
					}
				}else{
					if(streetDirectionMap.get(fields[i]) != null){
						postStreetDirectionPos = i;
						postStreetDirection = fields[i];
						postStreetDirectionRange = 1;
					}
				}
			}
			// check secondary unit
			for(int i = 2; i < fields.length; i++){
				// Check secondary unit
				if(secondaryUnitMap.get(fields[i]) != null){
					secondaryUnitPos = i;
					secondaryUnit= fields[i];
				}
			} 

			if(preStreetDirectionPos > 0){
				if(preStreetDirectionPos != 1){
					logger.error("Don't understand this address");
					return;	
				}
				address.setPreDir(preStreetDirectionNormalized);
				if(postStreetDirectionPos > 0){
					address.setPostDir(postStreetDirectionNormalized);
					for(int i = preStreetDirectionPos + preStreetDirectionRange; i < postStreetDirectionPos-1; i++){
						sb.append(fields[i]);
						sb.append(" ");
					}
					sb.append(fields[postStreetDirectionPos-1]); 

				}else{
					if(secondaryUnitPos > 0){
						for(int i = preStreetDirectionPos + preStreetDirectionRange; i < secondaryUnitPos-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[secondaryUnitPos-1]); 
					}else{
						for(int i = preStreetDirectionPos + preStreetDirectionRange; i < fields.length-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[fields.length-1]); 
					}
				}
			}else{
				if(postStreetDirectionPos > 0){
					address.setPostDir(postStreetDirectionNormalized);
					for(int i = 1; i < postStreetDirectionPos-1; i++){
						sb.append(fields[i]);
						sb.append(" ");
					}
					sb.append(fields[postStreetDirectionPos-1]); 
				}else{
					if(secondaryUnitPos > 0){
						for(int i = 1; i < secondaryUnitPos-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[secondaryUnitPos-1]); 
					}else{
						for(int i = 1; i < fields.length-1; i++){
							sb.append(fields[i]);
							sb.append(" ");
						}
						sb.append(fields[fields.length-1]); 
					}
				}
			}
		}
		address.setStreetName(sb.toString());
		StringBuilder completeAddress = new StringBuilder();
		if(address.isStreetTypeBehind()){
			completeAddress.append(address.getStreetNumber());
			completeAddress.append(address.getStreetName());
			if(address.getPreDir() != null)
				completeAddress.append(address.getPreDir());
			if(address.getStreetType() != null)
				completeAddress.append(address.getStreetType());
			if(address.getPostDir() != null)
				completeAddress.append(address.getPostDir());
			completeAddress.append(address.getCity());
			completeAddress.append(address.getState());
		}else{
			completeAddress.append(address.getStreetNumber());
			if(address.getPreDir() != null)
				completeAddress.append(address.getPreDir());
			if(address.getStreetType() != null)
				completeAddress.append(address.getStreetType());
			completeAddress.append(address.getStreetName());
			if(address.getPostDir() != null)
				completeAddress.append(address.getPostDir());
			completeAddress.append(address.getCity());
			completeAddress.append(address.getState());
		}
		address.setCompleteAddress(completeAddress.toString().replaceAll(" ", "").toUpperCase());
	}

	@Override
	public Address parse(String addressLine1) {
		Address address = new Address();
		address.setAddressLine1(addressLine1);
		parse(address);
		return address;
	}

}
